# -*- coding: utf-8 -*-

import os
import sys
import sqlite3
import hashlib
import time
import re
from datetime import datetime

# 避免循环导入，在需要时动态导入
# from operation_logger import record_login, record_logout, record_password_change, record_security_event

# 导入数据库工具类
from db_utils import DatabaseUtils
from PyQt5.QtWidgets import (
    QDialog, QLabel, QLineEdit,
    QPushButton, QVBoxLayout, QHBoxLayout, QMessageBox, QFrame, QComboBox, QApplication,
    QProgressBar, QWidget
)
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtGui import QFont, QPixmap, QIcon, QColor


class PasswordUtils:
    """密码工具类 - 提供密码加密和验证功能"""
    
    @staticmethod
    def hash_password(password):
        """对密码进行哈希处理
        
        参数:
            password: 原始密码
            
        返回:
            str: 哈希后的密码
        """
        # 使用MD5哈希 + 盐值
        salt = os.urandom(16).hex()
        hash_obj = hashlib.md5((password + salt).encode('utf-8'))
        return f"{hash_obj.hexdigest()}:{salt}"
    
    @staticmethod
    def verify_password(plain_password, hashed_password):
        """验证密码
        
        参数:
            plain_password: 明文密码
            hashed_password: 哈希后的密码（包含盐值）
            
        返回:
            bool: 密码是否匹配
        """
        # 检查hashed_password格式是否有效
        if ':' not in hashed_password:
            # 兼容旧的明文密码
            return plain_password == hashed_password
            
        # 分离哈希值和盐值
        stored_hash, salt = hashed_password.split(':', 1)
        # 计算明文密码的哈希值
        hash_obj = hashlib.md5((plain_password + salt).encode('utf-8'))
        return hash_obj.hexdigest() == stored_hash


class LoginDialog(QDialog):
    """用户登录对话框"""
    login_successful = pyqtSignal(str, str, int)
    
    def __init__(self):
        super().__init__()
        self.setWindowTitle('用户登录')
        self.setFixedSize(420, 360)  # 恢复原始高度
        self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowTitleHint)
        self.setWindowModality(Qt.ApplicationModal)

        
        self.current_user = None
        self.current_role = None
        self.current_user_id = None
        self.login_attempts = 0
        self.login_lock_time = 0
        self.lockout_time = 30  # 登录失败后的锁定时间（秒）
        self.max_attempts = 3  # 最大失败尝试次数
        self._current_theme = None  # 用于跟踪当前主题
        
        self.initUI()
        # 初始化当前主题值
        self._initializeTheme()
        self.applyStyles()
        # 确保密码输入框已创建后再调用
        self.setFocusToPasswordField()
        # updateLoginButtonState会在initUI中被适当调用
        
        # 初始化主题监听机制
        self.initThemeListener()
        
    def setFocusToPasswordField(self):
        """设置密码输入框获得焦点"""
        QTimer.singleShot(100, lambda: self.password_edit.setFocus())
    
    def initUI(self):
        """初始化登录界面"""
        # 统一的尺寸常量
        INPUT_HEIGHT = 32
        BUTTON_HEIGHT = 30  # 减少6个单位（从36到30）
        LABEL_WIDTH = 90
        SPACING = 16
        
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(40, 30, 40, 30)
        main_layout.setSpacing(24)  # 增加主布局间距，提升层次感
        
        # 标题区域（移除了Logo）
        title_layout = QVBoxLayout()
        title_layout.setAlignment(Qt.AlignCenter)
        title_layout.setSpacing(12)  # 标题区域内部间距
        
        title_content = self.get_software_title()
        title_label = QLabel(title_content)
        title_label.setObjectName('loginTitleLabel')
        title_label.setAlignment(Qt.AlignCenter)
        title_layout.addWidget(title_label)
        
        main_layout.addLayout(title_layout)
        
        form_frame = QFrame()
        form_frame.setObjectName('loginFormFrame')
        form_layout = QVBoxLayout(form_frame)
        form_layout.setContentsMargins(20, 20, 20, 20)
        form_layout.setSpacing(SPACING)
        
        # 用户名输入区域
        username_layout = QHBoxLayout()
        username_layout.setSpacing(10)
        username_label = QLabel('用户名:')
        username_label.setFixedWidth(LABEL_WIDTH)
        username_label.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
        
        self.username_edit = QComboBox()
        self.username_edit.setEditable(True)
        self.username_edit.setPlaceholderText('请选择或输入用户名')
        self.username_edit.setMinimumHeight(INPUT_HEIGHT)
        self.username_edit.setMaximumHeight(INPUT_HEIGHT)
        
        self.loadUsernames()
        self.username_edit.lineEdit().returnPressed.connect(lambda: self.password_edit.setFocus())
        self.username_edit.lineEdit().installEventFilter(self)
        self.username_edit.lineEdit().textEdited.connect(self.onUsernameTextEdited)
        
        username_layout.addWidget(username_label)
        username_layout.addWidget(self.username_edit)
        form_layout.addLayout(username_layout)
        
        # 密码输入区域
        password_layout = QHBoxLayout()
        password_layout.setSpacing(10)
        password_label = QLabel('密码:')
        password_label.setFixedWidth(LABEL_WIDTH)
        password_label.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
        
        self.password_edit = QLineEdit()
        self.password_edit.setEchoMode(QLineEdit.Password)
        self.password_edit.setPlaceholderText('请输入密码')
        self.password_edit.setMinimumHeight(INPUT_HEIGHT)
        self.password_edit.setMaximumHeight(INPUT_HEIGHT)
        self.password_edit.returnPressed.connect(self.onLoginClick)
        self.password_edit.textChanged.connect(self.updateLoginButtonState)
        
        password_layout.addWidget(password_label)
        password_layout.addWidget(self.password_edit)
        form_layout.addLayout(password_layout)
        
        # 登录锁定进度条（默认隐藏）
        self.lock_progress_widget = QWidget()
        self.lock_progress_layout = QHBoxLayout(self.lock_progress_widget)
        self.lock_progress_layout.setContentsMargins(LABEL_WIDTH + 10, 0, 0, 0)  # 与输入框对齐
        self.lock_progress_bar = QProgressBar()
        self.lock_progress_bar.setMinimumHeight(8)
        self.lock_progress_bar.setRange(0, self.lockout_time)
        self.lock_progress_bar.setValue(0)
        self.lock_progress_bar.setTextVisible(False)
        self.lock_progress_layout.addWidget(self.lock_progress_bar)
        self.lock_progress_widget.setEnabled(False)
        self.lock_progress_widget.hide()
        form_layout.addWidget(self.lock_progress_widget)
        
        # 按钮区域
        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(16)
        btn_layout.setContentsMargins(0, 8, 0, 10)  # 增加按钮与上方元素的距离
        
        self.login_btn = QPushButton('登录')
        self.login_btn.setObjectName('login_btn')
        self.login_btn.setFixedHeight(BUTTON_HEIGHT)
        # 设置固定宽度，比原来减少6个单位（从86到80再到76）
        self.login_btn.setFixedWidth(76)
        self.login_btn.clicked.connect(self.onLoginClick)
        self.login_btn.setEnabled(False)
        
        cancel_btn = QPushButton('取消')
        cancel_btn.setFixedHeight(BUTTON_HEIGHT)
        # 设置固定宽度，比原来减少6个单位（从86到80再到76）
        cancel_btn.setFixedWidth(76)
        cancel_btn.clicked.connect(self.reject)
        
        btn_layout.addWidget(self.login_btn)
        btn_layout.addWidget(cancel_btn)
        
        # 调整按钮布局，确保与整体设计协调
        btn_layout.setContentsMargins(0, 8, 0, 10)  # 设置与框架底部的距离为10个单位
        form_layout.addLayout(btn_layout)
        
        main_layout.addWidget(form_frame)
        
        # 底部区域 - 使用配置驱动的方式显示版本信息和版权声明
        footer_container = QWidget()
        footer_layout = QVBoxLayout(footer_container)
        footer_layout.setContentsMargins(0, 0, 0, 0)
        footer_layout.setSpacing(4)  # 紧凑的间距
        footer_layout.setAlignment(Qt.AlignCenter)
        
        # 当前数据库标签 - 移动到版本号显示区域的正上方
        self.db_label = QLabel()
        self.db_label.setObjectName('db_label')  # 设置对象名以便应用样式
        self.update_database_label()  # 初始化数据库标签内容
        self.db_label.setAlignment(Qt.AlignCenter)
        self.db_label.setCursor(Qt.PointingHandCursor)  # 设置鼠标指针为手形
        self.db_label.mousePressEvent = lambda event: self.selectDatabase()
        footer_layout.addWidget(self.db_label)
        # 设置与版本号标签之间的垂直间距为10像素
        footer_layout.addSpacing(10)
        
        # 版本信息标签 - 从配置获取，使用宽度自适应设计
        version_info = self.get_software_info()
        version_label = QLabel(version_info)
        version_label.setObjectName('loginVersionLabel')
        version_label.setAlignment(Qt.AlignCenter)
        version_label.setWordWrap(False)  # 单行显示以获得准确的sizeHint
        
        # 允许标签宽度根据内容自动调整，同时保持居中对齐
        version_label.setMinimumWidth(0)  # 移除最小宽度限制
        
        # 计算并设置合适的宽度，确保完全包裹内容
        version_label.adjustSize()
        
        footer_layout.addWidget(version_label)
        
        # 版权信息标签 - 从配置获取，使用宽度自适应设计
        copyright_info = self.get_copyright_info()
        if copyright_info:
            copyright_label = QLabel(copyright_info)
            copyright_label.setObjectName('loginCopyrightLabel')
            copyright_label.setAlignment(Qt.AlignCenter)
            copyright_label.setWordWrap(False)  # 单行显示以获得准确的sizeHint
            
            # 允许标签宽度根据内容自动调整
            copyright_label.setMinimumWidth(0)  # 移除最小宽度限制
            
            # 计算并设置合适的宽度
            copyright_label.adjustSize()
            
            footer_layout.addWidget(copyright_label)
        
        # 添加到底部区域
        main_layout.addWidget(footer_container)
        # 设置弹性空间，确保底部区域始终位于窗口底部
        main_layout.addStretch(1)
    
    # 移除了setupLogo方法，因为不再需要登录窗口的图标
    
    def get_software_title(self):
        """获取软件品牌和名称"""
        conn = None
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            cursor.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='system_params'")
            if cursor.fetchone()[0] == 0:
                return '门面租赁管理系统'
            
            cursor.execute("SELECT value FROM system_params WHERE key='software_brand'")
            brand_result = cursor.fetchone()
            software_brand = brand_result[0] if brand_result else ''
            
            cursor.execute("SELECT value FROM system_params WHERE key='software_name'")
            name_result = cursor.fetchone()
            software_name = name_result[0] if name_result else ''
            
            if software_brand and software_name:
                return f'{software_brand}{software_name}'
            elif software_name:
                return software_name
            else:
                return '门面租赁管理系统'
        except Exception as e:
            from logger_module import log_error
            log_error(f"获取软件标题错误: {str(e)}")
            return '门面租赁管理系统'
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
                
    def get_current_database_name(self):
        """获取当前数据库名称"""
        from config_utils import ConfigManager
        import os
        
        try:
            db_path = ConfigManager.get_database_path()
            if db_path and os.path.exists(db_path):
                return os.path.basename(db_path)
            else:
                return "未设置"
        except Exception as e:
            from logger_module import log_error
            log_error(f"获取数据库名称错误: {str(e)}")
            return "未知"
    
    def get_software_info(self):
        """获取软件版本和开发时间，采用配置驱动方式"""
        conn = None
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 检查system_params表是否存在
            cursor.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='system_params'")
            if cursor.fetchone()[0] == 0:
                return '版本 1.3'
            
            # 从数据库配置获取版本信息
            cursor.execute("SELECT value FROM system_params WHERE key='software_version'")
            version_result = cursor.fetchone()
            software_version = version_result[0] if version_result else '1.3'
            
            # 从数据库配置获取开发时间
            cursor.execute("SELECT value FROM system_params WHERE key='development_time'")
            dev_time_result = cursor.fetchone()
            development_time = dev_time_result[0] if dev_time_result else ''
            
            # 格式化返回结果
            if development_time:
                return f'版本 {software_version} | 开发时间: {development_time}'
            else:
                return f'版本 {software_version}'
        except Exception as e:
            from logger_module import log_error
            log_error(f"获取软件信息错误: {str(e)}")
            return '版本 1.3'
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
    
    def get_copyright_info(self):
        """获取版权信息，从配置中读取"""
        conn = None
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            
            # 检查system_params表是否存在
            cursor.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='system_params'")
            if cursor.fetchone()[0] == 0:
                return None
            
            # 从数据库配置获取版权信息
            cursor.execute("SELECT value FROM system_params WHERE key='copyright_info'")
            copyright_result = cursor.fetchone()
            
            return copyright_result[0] if copyright_result else None
        except Exception as e:
            from logger_module import log_error
            log_error(f"获取版权信息错误: {str(e)}")
            return None
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
    
    def applyStyles(self):
        """应用界面样式 - 支持明暗主题切换，确保符合WCAG AA级对比度标准"""
        # 获取主题颜色配置（尝试检测系统是否使用暗色主题）
        is_dark_theme = self._is_dark_theme()
        
        # 根据主题类型设置颜色
        if is_dark_theme:
            # 深色主题颜色 - 符合WCAG AA级对比度标准
            dialog_bg = '#1a1a1a'  # 深色背景
            form_bg = '#2d2d2d'  # 表单背景
            text_color = '#ffffff'  # 主文本色（白色与深灰背景对比度约14:1）
            text_secondary = '#d0d0d0'  # 次要文本色（浅灰色与深灰背景对比度约10:1）
            text_muted = '#a0a0a0'  # 提示文本色（灰色与深灰背景对比度约7:1）
            border_color = '#404040'  # 边框色
            highlight_color = '#4CAF50'  # 强调色（绿色）
            highlight_hover = '#66BB6A'  # 悬停强调色
            highlight_pressed = '#45a049'  # 按下强调色
            input_bg = '#3a3a3a'  # 输入框背景
            button_bg = '#3a3a3a'  # 按钮背景
            button_text = '#d0d0d0'  # 按钮文本
            progress_bg = '#3a3a3a'  # 进度条背景
            link_color = '#64B5F6'  # 链接颜色
            link_hover = '#90CAF9'  # 链接悬停颜色
        else:
            # 明亮主题颜色
            dialog_bg = '#f5f5f5'  # 对话框背景
            form_bg = 'white'  # 表单背景
            text_color = '#333333'  # 主文本色
            text_secondary = '#555555'  # 次要文本色
            text_muted = '#999999'  # 提示文本色
            border_color = '#e0e0e0'  # 边框色
            highlight_color = '#4CAF50'  # 强调色
            highlight_hover = '#45a049'  # 悬停强调色
            highlight_pressed = '#3d8b40'  # 按下强调色
            input_bg = 'white'  # 输入框背景
            button_bg = '#f5f5f5'  # 按钮背景
            button_text = '#666666'  # 按钮文本
            progress_bg = '#f0f0f0'  # 进度条背景
            link_color = '#42A5F5'  # 链接颜色
            link_hover = '#1976D2'  # 链接悬停颜色
        
        # 构建样式表
        self.setStyleSheet(f'''
            /* 主窗口样式 */
            QDialog {{
                background-color: {dialog_bg};
                border-radius: 8px;
            }}
            
            /* 表单容器样式 */
            #loginFormFrame {{
                background-color: {form_bg};
                border-radius: 8px;
                border: 1px solid {border_color};
            }}
            
            /* 标签样式 */
            QLabel {{
                color: {text_color};
                font-size: 14px;
                font-family: 'Microsoft YaHei', sans-serif;
            }}
            
            /* 登录标题样式 */
            QLabel#loginTitleLabel {{
                font-size: 20px;
                font-weight: bold;
                color: {text_color};
            }}
            
            /* 版本信息标签样式 - 自适应宽度 */
            QLabel#loginVersionLabel {{
                color: {text_muted};
                font-size: 12px;
                min-height: 20px;  /* 确保有足够的高度显示内容 */
                padding-left: 5px;
                padding-right: 5px;
                /* 移除最大宽度限制，让标签能完全包裹内容 */
            }}
            
            /* 数据库标签样式 */
            #db_label {{
                color: {link_color};
                font-size: 10px;
                font-weight: normal;
                text-decoration: none;
            }}
            
            #db_label:hover {{
                color: {link_hover};
            }}
            
            /* 版权信息标签样式 - 自适应宽度 */
            QLabel#loginCopyrightLabel {{
                color: {text_muted};
                font-size: 11px;
                min-height: 18px;
                padding-left: 5px;
                padding-right: 5px;
                /* 移除最大宽度限制，让标签能完全包裹内容 */
            }}
            
            /* 输入框和下拉框基础样式 */
            QLineEdit,
            QComboBox {{
                border: 1px solid {border_color};
                border-radius: 4px;
                font-size: 14px;
                font-family: 'Microsoft YaHei', sans-serif;
                min-height: 32px;
                max-height: 32px;
                background-color: {input_bg};
                selection-background-color: {highlight_color};
                selection-color: white;
                color: {text_color};
            }}
            
            /* 输入框内边距 */
            QLineEdit {{
                padding-left: 12px;
                padding-right: 12px;
            }}
            
            /* 下拉框内边距 */
            QComboBox {{
                padding-left: 12px;
                padding-right: 25px;
            }}
            
            QComboBox::drop-down {{
                subcontrol-origin: padding;
                subcontrol-position: top right;
                width: 25px;
                border-left-width: 1px;
                border-left-color: {border_color};
                border-left-style: solid;
                border-top-right-radius: 4px;
                border-bottom-right-radius: 4px;
                background-color: {input_bg};
            }}
            
            QComboBox::down-arrow {{
                image: url(:/icons/arrow-down.png);
                width: 12px;
                height: 12px;
            }}
            
            /* 焦点样式 */
            QComboBox:focus,
            QLineEdit:focus {{
                border-color: {highlight_color};
                outline: none;
                border-width: 1px;
            }}
            
            /* 按钮基础样式 */
            QPushButton {{
                border-radius: 4px;
                font-size: 14px;
                font-weight: bold;
                font-family: 'Microsoft YaHei', sans-serif;
                min-height: 30px;
                max-height: 30px;
                padding-left: 16px;
                padding-right: 16px;
            }}
            
            /* 登录按钮样式 */
            QPushButton#login_btn {{
                background-color: {highlight_color};
                color: white;
                border: none;
            }}
            
            QPushButton#login_btn:hover:not(:disabled) {{
                background-color: {highlight_hover};
            }}
            
            QPushButton#login_btn:pressed:not(:disabled) {{
                background-color: {highlight_pressed};
            }}
            
            QPushButton#login_btn:disabled {{
                background-color: {border_color};
                color: {text_muted};
            }}
            
            /* 取消按钮样式 */
            QPushButton {{
                background-color: {button_bg};
                color: {button_text};
                border: 1px solid {border_color};
            }}
            
            QPushButton:hover:not(#login_btn):not(:disabled) {{
                background-color: {border_color};
                border-color: {highlight_color};
            }}
            
            QPushButton:pressed:not(#login_btn):not(:disabled) {{
                background-color: {border_color};
            }}
            
            /* 进度条样式 */
            QProgressBar {{
                border-radius: 4px;
                background-color: {progress_bg};
                text-align: center;
                color: {text_color};
            }}
            
            QProgressBar::chunk {{
                background-color: {highlight_color};
                border-radius: 4px;
            }}
        ''')
        
    def _get_theme_setting(self):
        """获取当前主题设置
        
        按以下顺序尝试获取主题设置：
        1. 配置文件根级别的theme键
        2. general部分的theme设置
        3. app_settings部分的theme设置
        
        返回:
            str: 主题名称，如'dark'、'default'等
        """
        try:
            # 尝试从配置文件读取主题设置
            from config_utils import ConfigManager
            config = ConfigManager.load_config()
            
            # 首先尝试从配置根级别读取theme（main.py保存的位置）
            theme_setting = config.get('theme', None)
            
            # 如果根级别没有，尝试从general部分获取
            if theme_setting is None:
                theme_setting = ConfigManager.get_setting('general', 'theme', None)
            
            # 如果general部分没有，尝试从app_settings获取
            if theme_setting is None:
                theme_setting = config.get('app_settings', {}).get('theme', 'default')
            
            return theme_setting.lower()
        except Exception:
            # 发生错误时默认为default主题
            return 'default'
    
    def _is_dark_theme(self):
        """检测当前系统是否使用暗色主题
        
        尝试从配置或环境中获取主题信息，如果没有找到则使用默认明亮主题
        
        返回:
            bool: True表示暗色主题，False表示明亮主题
        """
        return self._get_theme_setting() == 'dark'
            
    def initThemeListener(self):
        """初始化主题变化监听机制
        
        创建定时器定期检查主题设置的变化，并在主题变化时重新应用样式
        """
        # 创建定时器
        self.theme_listener_timer = QTimer(self)
        self.theme_listener_timer.timeout.connect(self.checkThemeChange)
        # 每500毫秒检查一次主题变化
        self.theme_listener_timer.start(500)
        
    def _initializeTheme(self):
        """初始化当前主题值
        
        在登录窗口初始化时获取并设置当前主题，确保主题切换功能正常工作
        """
        try:
            # 获取当前主题设置
            self._current_theme = self._get_theme_setting()
        except Exception:
            # 发生错误时设为默认值
            self._current_theme = 'default'
            
    def checkThemeChange(self):
        """检查主题是否发生变化
        
        比较当前主题设置与上次记录的主题，如果发生变化则重新应用样式
        """
        try:
            # 获取当前主题
            current_theme = self._get_theme_setting()
            
            # 检查主题是否发生变化
            if current_theme != self._current_theme:
                # 更新当前主题记录
                self._current_theme = current_theme
                # 重新应用样式
                self.applyStyles()
        except Exception:
            # 发生错误时不处理，继续监听
            pass
            
    def closeEvent(self, event):
        """关闭窗口时清理资源
        
        Args:
            event: 关闭事件
        """
        # 停止主题监听定时器
        if hasattr(self, 'theme_listener_timer'):
            self.theme_listener_timer.stop()
        # 调用父类的closeEvent方法
        super().closeEvent(event)
    
    def onLoginClick(self):
        """处理登录点击事件"""
        # 检查是否被锁定
        if self.isLocked():
            time_remaining = self.getLockRemainingTime()
            QMessageBox.warning(self, '登录锁定', 
                              f'登录尝试次数过多，请在{time_remaining}秒后重试')
            return
        
        username = self.username_edit.currentText().strip()
        password = self.password_edit.text().strip()
        
        if not username or not password:
            QMessageBox.warning(self, '警告', '用户名和密码不能为空！')
            return
        
        # 禁用登录按钮防止重复点击
        self.login_btn.setEnabled(False)
        
        # 验证用户
        result = self.validateUser(username, password)
        if isinstance(result, tuple) and result[0]:
            user_id = result[1]
            # 动态导入记录函数
            from operation_logger import record_login
            record_login(username, success=True)
            
            self.login_successful.emit(username, self.current_role, user_id)
            self.saveLoginRecord(username)
            self.accept()
        else:
            # 记录失败尝试
            self.login_attempts += 1
            reason = "用户名或密码错误"
            # 动态导入记录函数
            from operation_logger import record_login, record_security_event
            record_login(username, success=False, detail=reason)
            
            if self.login_attempts >= self.max_attempts:
                self.lockout_time = min(self.lockout_time * 2, 300)  # 锁定时间递增，最大5分钟
                self.login_lock_time = time.time()
                self.startLockTimer()
                record_security_event(None, f"用户{username}登录失败次数过多，已锁定{self.lockout_time}秒")
                QMessageBox.warning(self, '登录失败', 
                                  f'登录失败次数过多，账户将被锁定{self.lockout_time}秒')
            else:
                remaining_attempts = self.max_attempts - self.login_attempts
                QMessageBox.warning(self, '登录失败', 
                                  f'{reason}！剩余尝试次数: {remaining_attempts}')
                
            self.password_edit.clear()
            self.password_edit.setFocus()
            
    def selectDatabase(self):
        """选择数据库文件并切换数据库"""
        from db_utils import DatabaseUtils
        from config_utils import ConfigManager
        from PyQt5.QtWidgets import QFileDialog, QMessageBox
        from PyQt5.QtWidgets import QApplication
        import os
        import sqlite3
        from logger_module import log_info, log_error
        
        try:
            # 打开文件选择对话框
            file_path, _ = QFileDialog.getOpenFileName(
                self, 
                '选择数据库文件', 
                '', 
                'SQLite数据库文件 (*.db);;所有文件 (*.*)'
            )
            
            if file_path:
                # 路径验证
                if not os.path.exists(file_path):
                    QMessageBox.critical(self, '错误', '数据库文件不存在')
                    return
                
                if not os.access(file_path, os.R_OK | os.W_OK):
                    QMessageBox.critical(self, '错误', '数据库文件没有读写权限')
                    return
                
                # 验证选择的文件是否为有效的SQLite数据库
                try:
                    # 测试数据库连接
                    conn = sqlite3.connect(file_path)
                    cursor = conn.cursor()
                    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
                    tables = cursor.fetchall()
                    conn.close()
                    
                    # 检查是否包含必要的表
                    required_tables = ['contracts', 'users', 'reminder_settings']
                    found_tables = [table[0] for table in tables]
                    
                    missing_tables = [table for table in required_tables if table not in found_tables]
                    
                    if missing_tables:
                        reply = QMessageBox.question(
                            self,
                            '警告',
                            '所选数据库文件缺少以下必要表: ' + ', '.join(missing_tables) + '\n继续使用此数据库可能导致程序功能异常,是否继续?',
                            QMessageBox.Yes | QMessageBox.No,
                            QMessageBox.No
                        ) 
                        if reply != QMessageBox.Yes:
                            return
                    
                    # 使用ConfigManager设置新的数据库路径
                    success = ConfigManager.set_database_path(file_path)
                    
                    if success:
                        log_info(f"数据库路径设置成功: {file_path}")
                        
                        # 更新DatabaseUtils中的数据库路径
                        DatabaseUtils.set_db_path(file_path)
                        
                        # 尝试更新主窗口的数据库名称标签（如果存在）
                        for widget in QApplication.topLevelWidgets():
                            if hasattr(widget, 'update_db_name_label'):
                                widget.update_db_name_label()
                                log_info("主窗口数据库名称标签已更新")
                                break
                        
                        # 更新登录窗口中的数据库标签
                        self.update_database_label()
                        
                        # 提示用户重启程序以应用更改
                        QMessageBox.information(
                            self,
                            '成功',
                            '数据库选择成功!\n\n' 
                            '数据库路径已更新,状态栏显示的数据库名称也已更新。\n' 
                            '为了确保所有功能正常运行,请重启程序以完全应用新的数据库配置。'
                        )
                    else:
                        log_error(f"数据库路径设置失败: {file_path}")
                        QMessageBox.critical(self, '错误', '保存数据库路径失败,请检查文件权限')
                        
                except Exception as e:
                    log_error(f"数据库验证失败: {str(e)}")
                    QMessageBox.critical(
                        self,
                        '错误',
                        f'选择的文件不是有效的SQLite数据库: {str(e)}'
                    )
                    return
        
        except Exception as e:
            log_error(f"选择数据库过程异常: {str(e)}")
            QMessageBox.critical(
                self,
                '错误',
                f'选择数据库失败: {str(e)}'
            )
        finally:
            # 确保调用updateLoginButtonState而不是直接设置按钮状态
            # 这样可以保持登录按钮的启用逻辑一致性
            self.updateLoginButtonState()
    
    def isLocked(self):
        """检查是否处于登录锁定状态"""
        if self.login_lock_time == 0:
            return False
            
        return time.time() - self.login_lock_time < self.lockout_time
    
    def getLockRemainingTime(self):
        """获取锁定剩余时间"""
        if not self.isLocked():
            return 0
        
        elapsed = time.time() - self.login_lock_time
        return max(0, int(self.lockout_time - elapsed))
    
    def startLockTimer(self):
        """启动锁定计时器"""
        # 移除对布局对象的show和setEnabled调用，因为QHBoxLayout没有这些方法
        self.login_btn.setEnabled(False)
        self.username_edit.setEnabled(False)
        self.password_edit.setEnabled(False)
        
        self.lock_timer = QTimer(self)
        self.lock_timer.timeout.connect(self.updateLockProgress)
        self.lock_timer.start(1000)  # 每秒更新一次
        
        # 立即更新一次
        self.updateLockProgress()
    
    def updateLockProgress(self):
        """更新锁定进度条"""
        remaining = self.getLockRemainingTime()
        progress = self.lockout_time - remaining
        
        self.lock_progress_bar.setValue(progress)
        
        if remaining <= 0:
            # 锁定时间结束
            self.lock_timer.stop()
            self.lock_progress_layout.hide()
            self.login_btn.setEnabled(True)
            self.username_edit.setEnabled(True)
            self.password_edit.setEnabled(True)
            self.login_attempts = 0  # 重置尝试次数
    
    def loadUsernames(self):
        """从数据库加载所有用户名到下拉列表"""
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("SELECT username FROM users ORDER BY username")
            users = cursor.fetchall()
            DatabaseUtils.close_connection(conn)
            
            self.username_edit.clear()
            admin_exists = False
            for user in users:
                username = user[0]
                self.username_edit.addItem(username)
                if username == 'admin':
                    admin_exists = True
                    
            if admin_exists:
                self.username_edit.setCurrentText('admin')
        except Exception as e:
            from logger_module import log_error
            log_error(f"加载用户名列表错误: {str(e)}")
            self.username_edit.setCurrentText('admin')
    
    def eventFilter(self, source, event):
        """事件过滤器，用于捕获用户名输入框的焦点事件"""
        if source == self.username_edit.lineEdit() and event.type() == event.FocusIn:
            QTimer.singleShot(100, self.username_edit.showPopup)
        return super().eventFilter(source, event)
    
    def onUsernameTextEdited(self, text):
        """当用户名输入文本时自动展开下拉列表"""
        self.username_edit.showPopup()
    
    def update_database_label(self):
        """更新数据库标签内容"""
        db_name = self.get_current_database_name()
        self.db_label.setText(f"当前数据库: {db_name}")
        
    def updateLoginButtonState(self):
        """根据输入内容更新登录按钮状态"""
        username = self.username_edit.currentText().strip()
        password = self.password_edit.text()
        
        # 启用按钮的条件：用户名和密码都不为空，且未锁定
        self.login_btn.setEnabled(
            bool(username) and bool(password) and not self.isLocked()
        )
    
    def validateUser(self, username, password):
        """验证用户凭据"""
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("SELECT id, username, password, role FROM users WHERE username = ?", (username,))
            user = cursor.fetchone()
            DatabaseUtils.close_connection(conn)
            
            if user and PasswordUtils.verify_password(password, user[2]):
                self.current_user = user[1]
                self.current_role = user[3]
                self.current_user_id = user[0]
                return True, user[0]
            
            return False
        except Exception as e:
            QMessageBox.critical(self, '错误', f'数据库连接失败: {str(e)}')
            return False
    
    def saveLoginRecord(self, username):
        """保存登录记录"""
        try:
            timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            from logger_module import log_info
            log_info(f"用户 {username} 于 {timestamp} 登录系统")
        except Exception:
            pass


class PasswordChangeDialog(QDialog):
    """密码修改对话框"""
    password_changed = pyqtSignal()
    
    def __init__(self, username):
        super().__init__()
        self.username = username
        self.setWindowTitle('修改密码')
        self.setFixedSize(420, 340)
        self.setWindowModality(Qt.ApplicationModal)
        self.initUI()
        self.applyStyles()
    
    def initUI(self):
        """初始化密码修改界面"""
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(40, 30, 40, 30)
        main_layout.setSpacing(20)
        
        title_label = QLabel(f'用户 {self.username} - 修改密码')
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setFont(QFont('Microsoft YaHei', 16, QFont.Bold))
        main_layout.addWidget(title_label)
        
        old_password_layout = QHBoxLayout()
        old_password_label = QLabel('旧密码:')
        old_password_label.setFixedWidth(100)
        self.old_password_edit = QLineEdit()
        self.old_password_edit.setEchoMode(QLineEdit.Password)
        self.old_password_edit.returnPressed.connect(self.onChangeClick)
        old_password_layout.addWidget(old_password_label)
        old_password_layout.addWidget(self.old_password_edit)
        main_layout.addLayout(old_password_layout)
        
        new_password_layout = QHBoxLayout()
        new_password_label = QLabel('新密码:')
        new_password_label.setFixedWidth(100)
        self.new_password_edit = QLineEdit()
        self.new_password_edit.setEchoMode(QLineEdit.Password)
        self.new_password_edit.setPlaceholderText('请输入8-20位密码')
        self.new_password_edit.textChanged.connect(self.validatePasswordStrength)
        new_password_layout.addWidget(new_password_label)
        new_password_layout.addWidget(self.new_password_edit)
        main_layout.addLayout(new_password_layout)
        
        # 密码强度指示器
        self.password_strength_layout = QHBoxLayout()
        self.password_strength_layout.setContentsMargins(100, 0, 0, 0)
        
        self.strength_label = QLabel('密码强度:')
        self.strength_label.setFixedWidth(60)
        self.strength_label.setStyleSheet('font-size: 12px;')
        
        self.strength_meter = QProgressBar()
        self.strength_meter.setMinimumHeight(8)
        self.strength_meter.setRange(0, 100)
        self.strength_meter.setValue(0)
        self.strength_meter.setTextVisible(False)
        
        self.password_strength_layout.addWidget(self.strength_label)
        self.password_strength_layout.addWidget(self.strength_meter)
        main_layout.addLayout(self.password_strength_layout)
        
        confirm_password_layout = QHBoxLayout()
        confirm_password_label = QLabel('确认新密码:')
        confirm_password_label.setFixedWidth(100)
        self.confirm_password_edit = QLineEdit()
        self.confirm_password_edit.setEchoMode(QLineEdit.Password)
        self.confirm_password_edit.returnPressed.connect(self.onChangeClick)
        confirm_password_layout.addWidget(confirm_password_label)
        confirm_password_layout.addWidget(self.confirm_password_edit)
        main_layout.addLayout(confirm_password_layout)
        
        # 密码要求提示
        requirements_label = QLabel('密码要求: 至少8位，包含字母和数字')
        requirements_label.setStyleSheet('font-size: 12px; color: #666;')
        requirements_label.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(requirements_label)
        
        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(10)
        
        self.change_btn = QPushButton('修改')
        self.change_btn.setFixedHeight(40)
        self.change_btn.clicked.connect(self.onChangeClick)
        btn_layout.addWidget(self.change_btn)
        
        cancel_btn = QPushButton('取消')
        cancel_btn.setFixedHeight(40)
        cancel_btn.clicked.connect(self.reject)
        btn_layout.addWidget(cancel_btn)
        
        main_layout.addLayout(btn_layout)
    
    def applyStyles(self):
        """应用界面样式"""
        self.setStyleSheet('''
            QDialog {
                background-color: #f5f5f5;
                border-radius: 8px;
            }
            QLabel {
                color: #333;
                font-size: 14px;
            }
            QLineEdit {
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 6px 12px;
                font-size: 14px;
                min-height: 28px;
            }
            QLineEdit:focus {
                border-color: #4CAF50;
                outline: none;
            }
            QPushButton {
                border-radius: 4px;
                font-size: 14px;
                font-weight: bold;
                min-height: 40px;
            }
            QPushButton:first-child {
                background-color: #4CAF50;
                color: white;
                border: none;
            }
            QPushButton:first-child:hover {
                background-color: #388E3C;
            }
            QPushButton:last-child {
                background-color: #f0f0f0;
                color: #333;
                border: 1px solid #ddd;
            }
            QPushButton:last-child:hover {
                background-color: #e0e0e0;
            }
        ''')
    
    def validatePasswordStrength(self, password):
        """验证密码强度"""
        strength = 0
        
        # 长度检查
        if len(password) >= 8:
            strength += 25
        if len(password) >= 12:
            strength += 25
        
        # 字符类型检查
        if re.search(r'[A-Z]', password):
            strength += 15
        if re.search(r'[a-z]', password):
            strength += 15
        if re.search(r'[0-9]', password):
            strength += 15
        if re.search(r'[^A-Za-z0-9]', password):
            strength += 5
        
        self.strength_meter.setValue(strength)
        
        # 根据强度设置颜色
        if strength < 40:
            self.strength_meter.setStyleSheet('QProgressBar::chunk { background-color: #f44336; }')
        elif strength < 70:
            self.strength_meter.setStyleSheet('QProgressBar::chunk { background-color: #ff9800; }')
        else:
            self.strength_meter.setStyleSheet('QProgressBar::chunk { background-color: #4CAF50; }')
    
    def onChangeClick(self):
        """处理修改密码点击事件"""
        old_password = self.old_password_edit.text().strip()
        new_password = self.new_password_edit.text().strip()
        confirm_password = self.confirm_password_edit.text().strip()
        
        user_id = None
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("SELECT id FROM users WHERE username = ?", (self.username,))
            result = cursor.fetchone()
            if result:
                user_id = result[0]
            DatabaseUtils.close_connection(conn)
        except Exception:
            pass
        
        if not old_password or not new_password or not confirm_password:
            QMessageBox.warning(self, '警告', '所有密码字段不能为空！')
            return
        
        # 验证密码长度和复杂度
        if len(new_password) < 8:
            QMessageBox.warning(self, '警告', '新密码长度至少为8个字符！')
            return
            
        if not re.search(r'[A-Za-z]', new_password) or not re.search(r'[0-9]', new_password):
            QMessageBox.warning(self, '警告', '新密码必须包含字母和数字！')
            return
        
        if new_password != confirm_password:
            if user_id:
                record_password_change(user_id, self.username, success=False, reason="两次输入的新密码不一致")
            QMessageBox.warning(self, '警告', '两次输入的新密码不一致！')
            return
        
        if not self.validateOldPassword(old_password):
            if user_id:
                # 动态导入记录函数
                from operation_logger import record_password_change
                record_password_change(user_id, self.username, success=False, reason="旧密码错误")
            QMessageBox.warning(self, '警告', '旧密码错误！')
            self.old_password_edit.clear()
            self.old_password_edit.setFocus()
            return
        
        if self.updatePassword(new_password):
            if user_id:
                # 动态导入记录函数
                from operation_logger import record_password_change
                record_password_change(user_id, self.username, success=True)
            QMessageBox.information(self, '成功', '密码修改成功！')
            self.password_changed.emit()
            self.accept()
        else:
            if user_id:
                # 动态导入记录函数
                from operation_logger import record_password_change
                record_password_change(user_id, self.username, success=False, reason="数据库更新失败")
            QMessageBox.critical(self, '错误', '密码修改失败！')
    
    def validateOldPassword(self, old_password):
        """验证旧密码"""
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("SELECT password FROM users WHERE username = ?", (self.username,))
            result = cursor.fetchone()
            DatabaseUtils.close_connection(conn)
            
            # 使用PasswordUtils.verify_password进行密码验证，兼容明文和哈希密码
            return result and PasswordUtils.verify_password(old_password, result[0])
        except Exception as e:
            from logger_module import log_error
            log_error(f"验证旧密码错误: {str(e)}")
            return False
    
    def updatePassword(self, new_password):
        """更新密码"""
        try:
            # 对新密码进行哈希处理
            hashed_password = PasswordUtils.hash_password(new_password)
            
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("UPDATE users SET password = ? WHERE username = ?", 
                          (hashed_password, self.username))
            conn.commit()
            DatabaseUtils.close_connection(conn)
            return True
        except Exception as e:
            from logger_module import log_error
            log_error(f"更新密码错误: {str(e)}")
            return False


class SystemSettingPasswordDialog(QDialog):
    """系统设置密码验证对话框"""
    def __init__(self, username):
        super().__init__()
        self.username = username
        self.setWindowTitle('系统设置验证')
        self.setFixedSize(420, 260)
        self.setWindowModality(Qt.ApplicationModal)
        self.initUI()
        self.applyStyles()
    
    def initUI(self):
        """初始化密码验证界面"""
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(40, 30, 40, 30)
        main_layout.setSpacing(20)
        
        title_label = QLabel('系统设置安全验证')
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setFont(QFont('Microsoft YaHei', 16, QFont.Bold))
        main_layout.addWidget(title_label)
        
        info_label = QLabel(f'用户 {self.username}，请输入您的密码以访问系统设置')
        info_label.setAlignment(Qt.AlignCenter)
        info_label.setWordWrap(True)
        main_layout.addWidget(info_label)
        
        password_layout = QHBoxLayout()
        password_label = QLabel('密码:')
        password_label.setFixedWidth(80)
        self.password_edit = QLineEdit()
        self.password_edit.setEchoMode(QLineEdit.Password)
        self.password_edit.setPlaceholderText('请输入密码')
        self.password_edit.returnPressed.connect(self.onConfirmClick)
        password_layout.addWidget(password_label)
        password_layout.addWidget(self.password_edit)
        main_layout.addLayout(password_layout)
        
        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(10)
        
        self.confirm_btn = QPushButton('确认')
        self.confirm_btn.setFixedHeight(40)
        self.confirm_btn.clicked.connect(self.onConfirmClick)
        btn_layout.addWidget(self.confirm_btn)
        
        cancel_btn = QPushButton('取消')
        cancel_btn.setFixedHeight(40)
        cancel_btn.clicked.connect(self.reject)
        btn_layout.addWidget(cancel_btn)
        
        main_layout.addLayout(btn_layout)
    
    def applyStyles(self):
        """应用界面样式"""
        self.setStyleSheet('''
            QDialog {
                background-color: #f0f0f0;
            }
            QLabel {
                color: #333;
                font-size: 14px;
            }
            QLineEdit {
                border: 1px solid #ddd;
                border-radius: 4px;
                font-size: 14px;
                padding: 8px 12px;
                min-height: 32px;
            }
            QLineEdit:focus {
                border-color: #4CAF50;
                outline: none;
            }
            QPushButton {
                border-radius: 4px;
                font-size: 14px;
                font-weight: bold;
                min-height: 40px;
            }
            QPushButton:first-child {
                background-color: #4CAF50;
                color: white;
                border: none;
            }
            QPushButton:first-child:hover {
                background-color: #388E3C;
            }
            QPushButton:first-child:pressed {
                background-color: #2E7D32;
            }
            QPushButton:last-child {
                background-color: #f0f0f0;
                color: #333;
                border: 1px solid #ddd;
            }
            QPushButton:last-child:hover {
                background-color: #e0e0e0;
            }
        ''')
    
    def onConfirmClick(self):
        """处理确认点击事件"""
        password = self.password_edit.text().strip()
        
        if not password:
            QMessageBox.warning(self, '警告', '密码不能为空！')
            return
        
        if self.validatePassword(password):
            self.accept()
        else:
            QMessageBox.warning(self, '验证失败', '密码错误，请重新输入！')
            self.password_edit.clear()
            self.password_edit.setFocus()
            
    def validatePassword(self, password):
        """验证用户密码"""
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("SELECT password FROM users WHERE username = ?", (self.username,))
            result = cursor.fetchone()
            DatabaseUtils.close_connection(conn)
            
            # 使用PasswordUtils.verify_password进行密码验证，兼容明文和哈希密码
            return result and PasswordUtils.verify_password(password, result[0])
        except Exception:
            QMessageBox.critical(self, '错误', '验证过程中发生错误！')
            return False


class UserAuthManager:
    """用户认证管理器"""
    def __init__(self):
        self.current_user = None
        self.current_role = None
        self.current_user_id = None
        self.session_start_time = None
        self.last_activity_time = None
        self.session_timeout = 30 * 60  # 30分钟会话超时
    
    def login(self):
        """显示登录对话框并验证用户"""
        login_dialog = LoginDialog()
        
        def on_login_successful(username, role, user_id):
            self.current_user = username
            self.current_role = role
            self.current_user_id = user_id
            self.session_start_time = time.time()
            self.last_activity_time = time.time()
        
        login_dialog.login_successful.connect(on_login_successful)
        
        return login_dialog.exec_() == QDialog.Accepted
    
    def logout(self):
        """注销用户"""
        user_id = None
        username = self.current_user
        try:
            conn = DatabaseUtils.get_connection()
            cursor = conn.cursor()
            cursor.execute("SELECT id FROM users WHERE username = ?", (username,))
            result = cursor.fetchone()
            if result:
                user_id = result[0]
            DatabaseUtils.close_connection(conn)
        except Exception as e:
            from logger_module import log_error
            log_error(f"注销时获取用户ID错误: {str(e)}")
        
        if username and user_id:
            # 动态导入记录函数
            from operation_logger import record_logout
            record_logout(username, detail={'user_id': user_id})
        
        # 清除会话信息
        self.current_user = None
        self.current_role = None
        self.current_user_id = None
        self.session_start_time = None
        self.last_activity_time = None
    
    def is_authenticated(self):
        """检查用户是否已认证且会话未超时"""
        if self.current_user is None:
            return False
        
        # 检查会话是否超时
        if self.last_activity_time and time.time() - self.last_activity_time > self.session_timeout:
            # 会话超时，自动注销
            self.logout()
            return False
            
        # 更新最后活动时间
        self.last_activity_time = time.time()
        return True
    
    def has_permission(self, required_role):
        """检查用户是否有特定权限"""
        if not self.is_authenticated():
            return False
        
        # 管理员拥有所有权限
        if self.current_role == '管理员':
            return True
        
        # 普通用户只能访问自己的角色权限
        return self.current_role == required_role
    
    def change_password(self):
        """显示修改密码对话框"""
        if not self.is_authenticated():
            return False
        
        dialog = PasswordChangeDialog(self.current_user)
        return dialog.exec_() == QDialog.Accepted
    
    def verify_system_setting_access(self):
        """验证系统设置访问权限"""
        if not self.is_authenticated():
            return False
        
        # 管理员无需二次验证
        if self.current_role == '管理员':
            return True
            
        dialog = SystemSettingPasswordDialog(self.current_user)
        return dialog.exec_() == QDialog.Accepted
    
    def refresh_session(self):
        """刷新会话（更新最后活动时间）"""
        self.last_activity_time = time.time()
    
    def get_session_duration(self):
        """获取当前会话持续时间（秒）"""
        if not self.session_start_time:
            return 0
        return int(time.time() - self.session_start_time)


# 创建全局认证管理器实例
auth_manager = UserAuthManager()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    
    # 应用全局主题，确保与main.py启动时的样式一致
    from modern_theme import apply_global_theme
    apply_global_theme(app)
    
    if auth_manager.login():
         from logger_module import log_info
         log_info(f"登录成功: {auth_manager.current_user}, 角色: {auth_manager.current_role}")
    else:
        pass  # 不再需要打印
    
    sys.exit(app.exec_())